__author__ = 'Muscle'
from mui.Widgets.muiimage import *
from mui.Widgets.muitext import *
from mui.Widgets.muitooltips import *
from mui.muicomponent import *
from mui.InternalUse.muicontainer import MUIList

_KEY_MSGTYPE_ = mui.muicomponent._KEY_MSGTYPE_

class PressBase:
    def __init__(self):
        self.pressed = False
        self.bind('Mouse Down', setattr, self, 'pressed', True, postevent = False, noarg = True)
        self.bind('Dbl Click', setattr, self, 'pressed', True, postevent = False, noarg = True)
        self.bind('Mouse Up', setattr, self, 'pressed', False, postevent = False, noarg = True)

class IconBase(TextBase, ImageBase):
    def __init__(self, **kwargs):
        TextBase.__init__(self, **kwargs)
        ImageBase.__init__(self)
        self.imgSize = 50, 50
        self.textGap = 0
        self.margin = 5, 5, 5, 5
        self.orientation = 'Vertical'
        self.autosize = True
        self.minSize = 10, 10

        for i in ['text', 'imgSize', 'textGap', 'margin', 'orientation', 'autosize', 'minSize']:
            self.changeEvent(i, self.onAutoSize)

    def onAutoSize(self):
        if self.autosize:
            tw, th = self.textSize
            iw, ih = self.imgSize
            if self.orientation == 'Vertical':
                self.width = max(self.minSize[0], max(tw, iw) + self.margin[0] + self.margin[2])
                self.height = max(self.minSize[1], th + self.textGap + ih + self.margin[1] + self.margin[3])
            else:
                self.width = max(self.minSize[0], tw + self.textGap + iw + self.margin[0] + self.margin[2])
                self.height = max(self.minSize[1], max(th, ih) + self.margin[1] + self.margin[3])

    def draw(self, renderer):
        left, top, right, bottom = self.margin[0], self.margin[1], self.width - self.margin[2], self.height - self.margin[3]
        tw, th = self.textSize
        iw, ih = self.imgSize

        if self.orientation == 'Vertical':
            tx = left
            if self.alignX == 'left':
                ix = left
            elif self.alignX == 'right':
                ix = right - iw
            else:
                ix = (right + left - iw) / 2
            w = right - left


            ty = min(top + ih + self.textGap, bottom - th)
            iy = top
            h = bottom - ty


        else:
            ty = top
            if self.alignY == 'top':
                iy = top
                ty = iy
            elif self.alignY == 'bottom':
                iy = bottom - ih
                ty = iy
            else:
                iy = (bottom + top - ih) / 2
                ty = iy
            h = bottom - top

            tx = min(left + iw + self.textGap, right - tw)
            ix = left
            w = right - tx

        imgRenderRect = (ix, iy, iw, ih)
        textRenderRect = (tx, ty, w, h)
        ImageBase.draw(self, renderer, imgRenderRect)
        TextBase.draw(self, renderer, textRenderRect)

class CheckBase:
    def __init__(self, **kwargs):
        self.checked = False
        self.bind('Mouse Up', self.toggleCheck, postevent=False, noarg = True)

    def toggleCheck(self):
        self.checked = not self.checked

class MUIButton(MUIComponent, PressBase, CommandBase, TipBase):
    def __init__(self, parent=None, **argd):
        MUIComponent.__init__(self, parent, **argd)
        PressBase.__init__(self)
        CommandBase.__init__(self, **argd)
        TipBase.__init__(self, **argd)

        self.bgPath_h= r'button\btn_h.png|(4,4,4,4)'
        self.bgPath_n= r'button\btn_n.png|(4,4,4,4)'
        self.bgPath_g= r'button\btn_g.png|(4,4,4,4)'
        self.bgPath_p= r'button\btn_p.png|(4,4,4,4)'
        self.background = self.bgPath_n
        self.changeEvent('isMouseOver', self._updateBg_ )
        self.changeEvent('enabled', self._updateBg_ )
        self.changeEvent('pressed', self._updateBg_ )


    def onKey(self, msgType, key, symbol, modifiers):
        if msgType == _KEY_MSGTYPE_.press:
            if symbol == VK_SPACE or symbol == VK_RETURN:
                self.onCmd()
                return True
        return super(MUIButton, self).onKey(msgType, key, symbol, modifiers)

    def _updateBg_(self):
        if self.enabled == False:
           self.background=self.bgPath_g
        else:
           if self.isMouseOver:
              if self.pressed:
                  self.background=self.bgPath_p
              else:
                  self.background=self.bgPath_h
           else:
              self.background=self.bgPath_n
        self.setDirty(True)

class MUITextButton(MUIButton, TextBase):
    """ TextButton = Button + Text
    """
    def __init__(self, parent=None, **kwargs):
        MUIButton.__init__(self, parent, **kwargs)
        TextBase.__init__(self, **kwargs)
        self.setDefault(**kwargs)

    def on_draw(self, renderer):
        super(MUITextButton, self).on_draw(renderer)
        TextBase.draw(self, renderer)

class MUIImageButton(MUIButton, ImageBase):
    def __init__(self, parent=None, **kwargs):
        MUIButton.__init__(self, parent, **kwargs)
        ImageBase.__init__(self)
        self.setDefault(**kwargs)

    def on_draw(self, renderer):
        super(MUIImageButton, self).on_draw(renderer)
        ImageBase.draw(self, renderer)


class MUIIconButton(MUIButton, IconBase):
    def __init__(self, parent=None, **kwargs):
        MUIButton.__init__(self, parent, **kwargs)
        IconBase.__init__(self, **kwargs)
        self.setDefault(**kwargs)

    def on_draw(self, render):
        super(MUIIconButton, self).on_draw(render)
        IconBase.draw(self, render)


class MUICheckButton(MUIComponent, CheckBase, CommandBase, PressBase):
    def __init__(self, parent=None, **argd):
        MUIComponent.__init__(self, parent, **argd)
        CheckBase.__init__(self, **argd)
        CommandBase.__init__(self, **argd)
        PressBase.__init__(self)
        self.bgPath_h= r'button\btn_h.png|(4,4,4,4)'
        self.bgPath_n= r'button\btn_n.png|(4,4,4,4)'
        self.bgPath_g= r'button\btn_g.png|(4,4,4,4)'
        self.bgPath_p= r'button\btn_p.png|(4,4,4,4)'
        self.changeEvent('checked', self._updateBg_, sync = True)
        self.changeEvent('isMouseOver', self._updateBg_, sync = True)
        self.changeEvent('enabled', self._updateBg_ )
        self.changeEvent('pressed', self._updateBg_)
        
    def _updateBg_(self):
        if self.enabled == False:
           self.background=self.bgPath_g
        else:
           if self.checked:
               self.background=self.bgPath_p
           else:
               if self.isMouseOver:
                  if self.pressed:
                      self.background=self.bgPath_p
                  else:
                      self.background=self.bgPath_h
               else:
                  self.background=self.bgPath_n
        self.setDirty(True)

    def onCmd(self):
        if self.command:
            self.dispatch_cmd(self.command, self.checked)


class MUICheckTextButton(MUICheckButton, TextBase):
    def __init__(self, parent=None, **kwargs):
        MUICheckButton.__init__(self, parent, **kwargs)
        TextBase.__init__(self, **kwargs)

    def on_draw(self, renderer):
        super(MUICheckTextButton, self).on_draw(renderer)
        TextBase.draw(self, renderer)

class MUICheckImageButton(MUICheckButton, ImageBase):
    def __init__(self, parent=None, **kwargs):
        MUICheckButton.__init__(self, parent, **kwargs)
        ImageBase.__init__(self)
        self.setDefault(**kwargs)

    def on_draw(self, renderer):
        super(MUICheckImageButton, self).on_draw(renderer)
        ImageBase.draw(self, renderer)

class MUICheckIconButton( MUICheckButton, IconBase):
    def __init__(self, parent=None, **kwargs):
        MUICheckButton.__init__(self, parent, **kwargs)
        IconBase.__init__(self, **kwargs)
        self.setDefault(**kwargs)

    def on_draw(self, render):
        super(MUICheckIconButton, self).on_draw(renderer)
        IconBase.draw(self, renderer)

class MUICheckbox(MUICheckButton, TextBase):
    def __init__(self, parent=None, **kwargs):
        MUICheckButton.__init__(self, parent, **kwargs)
        TextBase.__init__(self, **kwargs)
        self.checkImg = ''
        self.margin = 5
        self.offset = 2

        self.checkImgPath_c_h =  r'checkbox\checkbox_c_h.png'
        self.checkImgPath_c_n =  r'checkbox\checkbox_c_n.png'
        self.checkImgPath_c_g =  r'checkbox\checkbox_c_g.png'
        self.checkImgPath_c_p =  r'checkbox\checkbox_c_p.png'

        self.checkImgPath_n_h =  r'checkbox\checkbox_n_h.png'
        self.checkImgPath_n_n =  r'checkbox\checkbox_n_n.png'
        self.checkImgPath_n_g =  r'checkbox\checkbox_n_g.png'
        self.checkImgPath_n_p =  r'checkbox\checkbox_n_p.png'
        
        self.bgPath_h= r''
        self.bgPath_n= r''
        self.bgPath_g= r''
        self.bgPath_p= r''
        self.checkImg = self.checkImgPath_n_n

        self.autosize = True
        self.setDefault(**kwargs)
        self.alignX = 'left'
        self.onAutoSize()
        self.bind('Size Change', self.onAutoSize, noarg = True, postevent = False )
        self.changeEvent('text', self.onAutoSize)
        self.changeEvent('margin', self.onAutoSize)
        
    def _updateBg_(self):
        if self.checked:
            checkImgs = (self.checkImgPath_c_h, self.checkImgPath_c_n, self.checkImgPath_c_g, self.checkImgPath_c_p)
        else:
            checkImgs = (self.checkImgPath_n_h, self.checkImgPath_n_n, self.checkImgPath_n_g, self.checkImgPath_n_p)
        bgImgs = (self.bgPath_h, self.bgPath_n, self.bgPath_g, self.bgPath_p)
        src = [bgImgs,  checkImgs]
        target = ['background', 'checkImg']

        if self.enabled == False:
            for i in range(len(target)):
                setattr(self, target[i], src[i][2])
        else:
            if self.isMouseOver:
                if self.pressed:
                    for i in range(len(target)):
                        setattr(self, target[i], src[i][3])
                else:
                   for i in range(len(target)):
                        setattr(self, target[i], src[i][0])
            else:
                for i in range(len(target)):
                    setattr(self, target[i], src[i][1])
        self.setDirty(True)
        
    def __getTexPosition(self):
        return self.height - self.margin + self.offset, self.margin, self.width - self.margin, self.height - self.margin
    textPos = property(__getTexPosition)

    def onAutoSize(self):
        m = self.margin
        if self.autosize:
            tw, th = self.textSize
            self.size = tw + th + self.offset + m * 2, th + m * 2
        self.checkPos = m, m, self.height - m * 2, self.height - m * 2


    def hitTest(self, x, y):
        if not super(MUICheckbox, self).hitTest(x, y):
            return False
        elif self.alignX == 'center':
            if x > (self.height + self.offset + self.width + self.textSize[0]) / 2:
                return False
        elif self.alignX != 'right' :
            if x > self.height + self.offset + self.textSize[0]:
                return False
        return True

    def on_draw(self, renderer):
        super(MUICheckbox, self).on_draw(renderer)
        checkRect = (self.checkPos[0], self.checkPos[1], self.checkPos[2] + self.checkPos[0], self.checkPos[3] + self.checkPos[1])
        renderer.DrawBitmap(self.checkImg, checkRect, muiDX.NoStretch, self.opacity )
      
        textRect = self.height + self.offset, 0, self.width - self.offset, self.height

        TextBase.draw(self, renderer, textRect)

    def onKey(self, msgType, key, symbol, modifiers):
        if (msgType == _KEY_MSGTYPE_.press ):
            if symbol == VK_SPACE:
                self.checked = not self.checked
                self.onCmd()
                return True
        return super(MUICheckbox, self).onKey(msgType, key, symbol, modifiers)

class RadioBase:
    def __init__(self):
        self.changeEvent('checked', self.__onCheckedChanged, postevent = False)
        self.autoRemove( self.parent.bind('Select Changed', self.__onSyncGroup) )

    def __onCheckedChanged(self):
        if self.checked:
            self.parent.dispatch_event('Radio Changed', self)

    def __onSyncGroup(self, o):
        if self is not o:
            self.checked = False

class MUIRadioButton(MUICheckbox, RadioBase):
    def __init__(self, parent=None, **kwargs):
        MUICheckbox.__init__(self, parent, check = False, **kwargs)
        RadioBase.__init__(self)

        self.checkImgPath_c_h =  r'radioButton\radio_c_h.png'
        self.checkImgPath_c_n =  r'radioButton\radio_c_n.png'
        self.checkImgPath_c_g =  r'radioButton\radio_c_g.png'
        self.checkImgPath_c_p =  r'radioButton\radio_c_p.png'

        self.checkImgPath_n_h =  r'radioButton\radio_n_h.png'
        self.checkImgPath_n_n =  r'radioButton\radio_n_n.png'
        self.checkImgPath_n_g =  r'radioButton\radio_n_g.png'
        self.checkImgPath_n_p =  r'radioButton\radio_n_p.png'


        self.changeEvent('checked', self._updateBg_, sync = True)
        self.bgColor = (0,0,0,0)
    def onKey(self,  msgType, key, symbol, modifiers):
        if (msgType == _KEY_MSGTYPE_.press ):
            if symbol == VK_SPACE:
                if not self.checked:
                    self.checked = True
                    self.onCmd()
                return True
            return super(MUIRadioButton, self).onKey(msgType, key, symbol, modifiers)
        return False

class MUIGroupBase:
    """ GroupBase
    """
    def __init__(self):
        self.tabStop = False
        self.bind('Radio Changed', self.__onSomeoneChanged, postevent=False)

    def __onSomeoneChanged(self, obj):
        self.dispatch_event('Select Changed', obj)

class MUIGroup(MUIComponent, MUIGroupBase):
    def __init__(self, parent=None, **kwargs):
        MUIComponent.__init__(self, parent, **kwargs)
        MUIGroupBase.__init__(self)


class MUICombobox(MUIText, PressBase, TipBase):
    """ Combobox
    events:
       - Select Changed (index)
       - Data Changed

    ex:
    <pre>
    combobox = Combobox(self)                                                                                           
    combobox.removeItems()
    combobox.addItems(['Hello', 'World'])
    combobox.addItem('New item 1')
    combobox.removeItem('Wrold')
    </pre>
    """
    def __init__(self, parent=None, **argd):
        MUIText.__init__(self, parent, blind=False, tabStop=1000, **argd)
        PressBase.__init__(self)
        TipBase.__init__(self, **argd)
        self.margin = 0, 0, 0, 0
        self.focusImg = ''
        self.focusGamma = ''

        self.index = -1
        self.__data = MUIList()
        self.autoRemove( self.data.bind('Change', self.dispatch_event, 'Data Changed', postevent = False, noarg = True))

        self.menuStyle = None
        self.itemStyle = None

        self.changeEvent('enabled', self.__onEnableChanged, sync=False)
        self.changeEvent('index', self.__onChangeSelect, postevent=False, sync=True)
        self.changeEvent('text', self.__onTextChanging, postevent=False, sync=True)
        self.changeEvent('text', self.__onTextChanged, sync=True)
        self.bind('Data Changed', self.__onDataChanged, postevent=False)
        self.bind('Mouse Down', self.__onCombolist, noarg = True)

    #---------------------------------------------
    # property
    #---------------------------------------------
    def getTextPosition(self):
        return self.margin[0], self.margin[1], self.width - self.margin[2], self.height - self.margin[3]
    textPos = property(getTextPosition)

    def getData(self):
        return self.__data
    data = property(getData)

    def getSelectedData(self):
        if 0 <= self.index and self.index < len(self.data):
            return self.data[self.index]
        else:
            return None
    selectedData = property(getSelectedData)
    #---------------------------------------------
    # override function
    #---------------------------------------------
    def close(self):
        if hasattr(self, 'combolist'):
            self.combolist.onCancel()
            del self.combolist
        self.__data.close()
        self.__data = None
        super(Combobox, self).close()

    def onDraw(self, render):
        super(Combobox, self).onDraw(render)
        if self.focusImg and self.enabled and self.focus:
            t = render.GetTexture(self.focusImg, gamma=self.focusGamma)
            render.SetTexture(t)
            render.DrawRect(*self.localRect)

    #---------------------------------------------
    # operation
    #---------------------------------------------
    def addItem(self, i):
        self.data.append(i)

    def addItems(self, i):
        self.data.extend(i)

    def removeItems(self):
        del self.data[:]

    def removeItem(self, i):
        if i in self.data:
            self.data.remove(i)

    #---------------------------------------------
    # KXML syntax
    #---------------------------------------------
    def setContent(self, data, **keyword):
        parser = keyword.get('parser', None)
        d = eval(data, keyword)
        t = type(d)
        if t is tuple or t is list:
            for s in d:
                self.data.append(s)
        else:
            self.data.append(d)

    def setAttribute(self, name, strValue, **keyword):
        n = name.lower()
        if n == 'menustyle' or n == 'itemstyle':
            cls = strValue.strip()
            styles = keyword['parser'].stkAutoStyle[-1][2]['name']
            if cls in styles:
                styleCmd = styles[cls]
                styleCmd.macro = keyword['parser'].macro
                setattr(self, name, styleCmd)
        elif n == 'data' or n == 'list':
            self.setContent(strValue.strip(), **keyword)
        else:
            super(Combobox, self).setAttribute(name, strValue, **keyword)

    #---------------------------------------------
    # private function
    #---------------------------------------------
    def __onDataChanged(self):
        if self.data:
            if not self.selectedData:
                #self.index = 0
                object.__setattr__(self, 'index', 0)
        else:
            #self.index = -1
            object.__setattr__(self, 'index', -1)
        self.__onChangeSelect()

    def __onChangeSelect(self):
        self.text = unicode(self.selectedData) if self.selectedData else ''
        if self.selectedData:
            self.dispatch_event('Select Changed', self.index)

    def __onTextChanging(self):
        try:
            idx = self.data.index(self.text)
            object.__setattr__(self, 'index', idx)
        except:
            object.__setattr__(self, 'index', -1)

    def __onTextChanged(self):
        if self.tips != self.text:
            width = self.width - self.margin[2] - self.margin[0]
            if width < self.textSize[0]:
                self.tips = self.text
            else:
                self.tips = ''

    def __onEnableChanged(self):
        if not self.enabled and hasattr(self, 'combolist'):
            self.combolist.onCancel()

    def __onCombolist(self):
        if len(self.data) and not hasattr(self, 'combolist'):
            from Widgets.menu import PopupMenu, MenuItem
            self.combolist = m = PopupMenu(self.window)
            m.applyStyle(self.menuStyle)
            w = self.width
            for o in self.data:
                itm = MenuItem(m)
                itm.applyStyle(self.itemStyle)
                itm.align = self.align
                itm.iconWidth = 0
                itm.header = unicode(o)
                try:
                    itm.enabled = o.enabled
                except:
                    pass
                itm.command = str(self.data.index(o))
                itm.width = w
                if o == self.data[self.index]:
                    itm.setFocus()
            m.xy = self.local2global(0, self.height)
            m.width = w
            ret = m.doModal()
            if hasattr(self, 'combolist'):
                del self.combolist
            self.setFocus()
            if type(ret) is str or type(ret) is unicode:
                try:
                    self.index = int(ret)
                except:
                    pass

    def onCombolist(self):
        self.__onCombolist()

    #-------------------------------------------------
    # keyboard
    #-------------------------------------------------
    def onKey(self, key):
        if key == ' ':
            self.__onCombolist()
            return True
        elif key == 'UP':
            self.index = max( self.index - 1, 0 )
            return True
        elif key == 'DOWN':
            self.index = min( self.index + 1, len(self.data) - 1 )
            return True
        return super(Combobox, self).onKey(key)
